package com.startit.csv;

import java.io.IOException;
import java.io.LineNumberReader;
import java.io.Reader;
import java.lang.reflect.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import com.startit.csv.CSVField.DataType;
import com.startit.csv.exception.*;

public class CSVBeanReader<T> extends CSVAbstractReader<T> implements ICSVReader {
	protected Class<T> claz;
	
	public CSVBeanReader(Reader reader, CSVFormat format, Class claz) {
		super(reader,format);
		this.claz = claz;
		format.setMappingBean(this.claz);
	}
	
	@SuppressWarnings("unchecked")
	public<T> T readLine() throws IOException, TokenException,
			CSVReaderException, ValidationException {
		String[] r = this.readLineToStringArray();
		List<CSVField> fields = format.getFields();
		try {
			Object obj = claz.newInstance();
			int i = 0;
			for (CSVField f : fields) {
				Method m = getMethod(claz, f);
				Object arg = null;
				if (f.getDataType() != DataType.DATE) 
					arg = f.getArgClass().getConstructor(String.class).newInstance(r[i++]);
				else 
					arg = (new SimpleDateFormat(f.getDataFormatPattern())).parse(r[i++]);
				m.invoke(obj, arg);
			}
			return (T)obj;
		} catch (Exception e) {
			throw new CSVReaderException(e);
		}
	}
	
	private Method getMethod(Class claz, CSVField field)
			throws CSVReaderException {
		Method m = null;
		char[] name = field.getName().toCharArray();
		name[0] = ("" + name[0]).toUpperCase().charAt(0);
		switch (field.getDataType()) {
		case INT:
			m = getMethod(claz, "set" + new String(name), Integer.class);
			m = (m == null) ? getMethod(claz, "set" + new String(name),
					int.class) : m;
			break;
		case FLOAT:
			m = getMethod(claz, "set" + new String(name), Float.class);
			m = (m == null) ? getMethod(claz, "set" + new String(name),
					float.class) : m;
			break;
		case DATE:
			m = getMethod(claz, "set" + new String(name), Date.class);
			break;
		default:
			m = getMethod(claz, "set" + new String(name), String.class);
		}
		return m;
	}
	
	private Method getMethod(Class claz,String name,Class...classes) {
		try {
			return claz.getMethod(name, classes);
		} catch (Exception e) {
			return null;
		}
	}

}
